home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1998 January: Mac OS SDK / Dev.CD Jan 98 SDK2.toast / Development Kits (Disc 2) / QuickDraw GX / Programming Stuff / GXEdit Library & Doc / GXEditParagraph.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-04-10  |  39.2 KB  |  1,880 lines  |  [TEXT/MPS ]

  1. /*
  2.     File:                GXEditParagraph.c
  3.     
  4.     Contains:
  5.     
  6.     Written by:        Barton R. House
  7.     
  8.     Copyright:        © 1993 by Apple Computer, Inc., All rights reserved.
  9.     
  10. */
  11.  
  12. #include "GXEdit.h"
  13. #include "GXEditDebug.h"
  14. #include "GXEditDoc.h"
  15. #include "GXEditParagraph.h"
  16. #include "GXEditLine.h"
  17. #include "GXEditNewRun.h"
  18. #include "GXEditStyle.h"
  19. #include "GXEditSelection.h"
  20. #include "GXEditError.h"
  21.  
  22. /* GX includes */
  23. #include "graphics routines.h"
  24. #include "math routines.h"
  25. #include "graphics libraries.h"
  26. #include "layout routines.h"
  27.  
  28. static void     CalcOffsets(DocPtr dp, ParaPtr pp, short lineIndex);
  29. static void     CalcStarts(DocPtr dp, ParaPtr pp, short lineIndex);
  30.  
  31. static void    CalcRunOffsets(DocPtr dp, ParaPtr pp, short runIndex);
  32.  
  33. static void     ReflowParagraphAtIndex(DocPtr dp, ParaPtr pp, short lineIndex);
  34. static void     NewReflowParagraphAtIndex(DocPtr dp, ParaPtr pp, short lineIndex);
  35. static short    FindWordBreak(DocPtr dp, ParaPtr pp, short startOffset, short endOffset);
  36.  
  37. static void    CheckAttributes(DocPtr dp, NewRunPtr rp, AttrPtr ap);
  38.  
  39. static void    CleanUpRuns(DocPtr dp, ParaPtr pp, short runIndex);
  40.  
  41. void InsertParagraphText(DocPtr dp, ParaPtr pp, short paraOffset, void * text, short numText, short styleIndex)
  42. {
  43.     LinePtr            lp;
  44.     NewRunPtr        rp;
  45.     short            lineIndex;
  46.     short            lineOffset;
  47.     short            runIndex;
  48.     short            runOffset;
  49.     long                size;
  50.     
  51.     if(paraOffset < 0 || paraOffset > pp->numText)
  52.         gxEditPostError(dp, gx_edit_internal_fatal_error);
  53.         
  54.     /* insert the text into the runs */
  55.     
  56.     HLock((Handle) pp->runs);
  57.     
  58.     /* find the run and the offset */
  59.     
  60.     GetNewRunIndexAndOffset(dp, pp, paraOffset, &runIndex, &runOffset);
  61.     
  62.     /* add the text */
  63.     
  64.     rp = *pp->runs + runIndex;
  65.     
  66.     if(rp->styleIndex != styleIndex) {
  67.     
  68.         if(runOffset == 0) {
  69.         
  70.             if(runIndex && (rp-1)->styleIndex == styleIndex) {
  71.             
  72.                 runIndex--;
  73.                 runOffset = (rp-1)->numText;
  74.                 
  75.             } else {
  76.         
  77.                 pp->numRuns++;
  78.                 
  79.                 HUnlock((Handle) pp->runs);
  80.                 
  81.                 size = pp->numRuns * sizeof(NewRunRec);
  82.                 SetHandleSize((Handle) pp->runs, size);
  83.                 
  84.                 HLock((Handle) pp->runs);
  85.                 
  86.                 size = (pp->numRuns - runIndex - 1) * sizeof(NewRunRec);
  87.                 BlockMove((Ptr) (*pp->runs + runIndex), (Ptr) (*pp->runs + runIndex + 1), size);
  88.                 
  89.                 NewNewRun(dp, *pp->runs + runIndex, styleIndex);
  90.                 
  91.                 runOffset = 0;
  92.  
  93.             }
  94.             
  95.         } else if(runOffset == rp->numText) {
  96.         
  97.             if(runIndex < pp->numRuns - 1 && (rp+1)->styleIndex == styleIndex) {
  98.                 
  99.                 runIndex++;
  100.                 runOffset = 0;
  101.                 
  102.             } else {
  103.             
  104.                 runIndex++;
  105.                 
  106.                 pp->numRuns++;
  107.                 
  108.                 HUnlock((Handle) pp->runs);
  109.                 
  110.                 size = pp->numRuns * sizeof(NewRunRec);
  111.                 SetHandleSize((Handle) pp->runs, size);
  112.                 
  113.                 HLock((Handle) pp->runs);
  114.                 
  115.                 size = (pp->numRuns - runIndex - 1) * sizeof(NewRunRec);
  116.                 BlockMove((Ptr) (*pp->runs + runIndex), (Ptr) (*pp->runs + runIndex + 1), size);
  117.                 
  118.                 NewNewRun(dp, *pp->runs + runIndex, styleIndex);
  119.                 
  120.                 runOffset = 0;
  121.  
  122.             }
  123.             
  124.         } else {
  125.         
  126.             pp->numRuns += 2;
  127.             
  128.             HUnlock((Handle) pp->runs);
  129.             
  130.             size = pp->numRuns * sizeof(NewRunRec);
  131.             SetHandleSize((Handle) pp->runs, size);
  132.             
  133.             HLock((Handle) pp->runs);
  134.             
  135.             size = (pp->numRuns - runIndex - 3) * sizeof(NewRunRec);
  136.             BlockMove((Ptr) (*pp->runs + runIndex + 1), (Ptr) (*pp->runs + runIndex + 3), size);
  137.             
  138.             SplitNewRun(dp, *pp->runs + runIndex, runOffset, *pp->runs + runIndex + 2);
  139.             
  140.             NewNewRun(dp, *pp->runs + runIndex + 1, styleIndex);
  141.             
  142.             runIndex++;
  143.             runOffset = 0;
  144.             
  145.         }
  146.         
  147.         rp = *pp->runs + runIndex;
  148.     
  149.     }
  150.     
  151.     InsertNewRunText(dp, rp, runOffset, text, numText);
  152.     
  153.     HUnlock((Handle) pp->runs);
  154.     
  155.     /* insert the text into the lines */
  156.     
  157.     HLock((Handle) pp->lines);
  158.     
  159.     /* find the gxLine and the offset */
  160.     
  161.     GetLineIndexAndOffset(dp, pp, paraOffset, &lineIndex, &lineOffset, false);
  162.     
  163.     lp = *pp->lines + lineIndex;
  164.     
  165.     InsertDocLineText(dp, lp, lineOffset, numText);
  166.     
  167.     /* update the text count */
  168.     
  169.     pp->numText += numText;
  170.                             
  171.     HUnlock((Handle) pp->lines);
  172.     
  173.     CalcRunOffsets(dp, pp, runIndex);    
  174.     CalcOffsets(dp, pp, lineIndex);
  175.     
  176.     pp->dirty = true;        /* CalcStarts(dp, pp, lineIndex); */
  177.     
  178.     if(lineIndex > 0) lineIndex--;
  179.     
  180.     (*pp->lines)[lineIndex].reflow = true;
  181.     
  182.     pp->reflow = true;
  183.     
  184. }
  185.                                     
  186. void DrawParagraph(DocPtr dp, ParaPtr pp, long start, long end)
  187. {
  188.     LinePtr        lp;
  189.     short        lineIndex;
  190.     
  191.     if(pp->dirty)                /* we are using gxLine starts, check if paragraph is dirty */
  192.         CalcStarts(dp, pp, 0);
  193.     
  194.     HLock((Handle) pp->lines);
  195.     
  196.     for(lineIndex = 0, lp = *pp->lines; lineIndex < pp->numLines; lineIndex++, lp++)
  197.         if((pp->start + lp->start) < end && (pp->start + lp->start + GetLineHeight(dp, pp ,lp)) > start)
  198.             DrawDocLine(dp, pp, lp);
  199.         
  200.     HUnlock((Handle) pp->lines);
  201.     
  202.     pp->drawn = true;
  203.     
  204. }
  205.  
  206. void ReflowParagraph(DocPtr dp, ParaPtr pp)
  207. {
  208.     LinePtr            lp;
  209.     short            lineIndex;
  210.     
  211.     lp = *pp->lines;
  212.     
  213.     for(lineIndex=0; lineIndex < pp->numLines; lineIndex++, lp++)
  214.         if(lp->reflow) {
  215.             ReflowParagraphAtIndex(dp, pp, lineIndex);
  216.             break;
  217.         }
  218.         
  219.     pp->reflow = false;
  220. }
  221.  
  222. void gxEditNewParagraph(DocPtr dp, ParaPtr pp, short styleIndex)
  223. {
  224.     char            c;
  225.     
  226.     pp->numRuns = 1;
  227.     pp->runs = (NewRunHan) NewHandle(sizeof(NewRunRec));
  228.     
  229.     HLock((Handle) pp->runs);
  230.     
  231.     NewNewRun(dp, *pp->runs, styleIndex);
  232.     
  233.     pp->numLines = 1;
  234.     pp->lines = (LineHan) NewHandle(sizeof(LineRec));
  235.     
  236.     pp->layoutOptions = dp->currentLayoutOptions;
  237.     
  238.     HLock((Handle) pp->lines);
  239.     
  240.     NewDocLine(*pp->lines);
  241.     
  242.     /* add newline character */
  243.     c = '\r';
  244.     
  245.     InsertNewRunText(dp, *pp->runs, 0, &c, 1);
  246.     
  247.     InsertDocLineText(dp, *pp->lines, 0, 1);
  248.     
  249.     HUnlock((Handle) pp->runs);
  250.  
  251.     pp->start = 0;
  252.     pp->width = dp->lineWidth;
  253.     pp->docOffset = 0;
  254.     pp->numText = 1;
  255.     pp->drawn = false;
  256.     pp->reflow = true;
  257.     pp->height = GetLineHeight(dp, pp, *pp->lines);
  258.  
  259.     HUnlock((Handle) pp->lines);
  260.     
  261.  
  262. }
  263.  
  264. void HitTestParagraph(DocPtr dp, ParaPtr pp, Point where, short * paraOffsetPtr, Boolean * endOfLinePtr)
  265. {
  266.     LinePtr                lp;
  267.     short                lineIndex;
  268.     short                lineOffset;
  269.     short                paraOffset;
  270.     Boolean                endOfLine;
  271.     
  272.     if(pp->dirty)                /* we are using gxLine starts, check if paragraph is dirty */
  273.         CalcStarts(dp, pp, 0);
  274.     
  275.     HLock((Handle) pp->lines);
  276.     
  277.     lp = *pp->lines;
  278.     
  279.     paraOffset = 0;    /* in case of error */
  280.     endOfLine = false;
  281.     
  282.     if(dp->verticalText) {
  283.         for(lineIndex=0; lineIndex < pp->numLines; lineIndex++, lp++)
  284.             if(where.h >= lp->start && where.h < (lp->start + GetLineHeight(dp, pp, lp))) {
  285.             
  286.                 where.h -= lp->start;
  287.                 
  288.                 lineOffset = HitTestDocLine(dp, pp, lp, where);
  289.                 
  290.                 if(lineOffset == lp->numText)
  291.                     endOfLine = true;
  292.                     
  293.                 paraOffset = lineOffset + lp->paraOffset;
  294.                 break;
  295.             }
  296.     } else {
  297.         for(lineIndex=0; lineIndex < pp->numLines; lineIndex++, lp++)
  298.             if(where.v >= lp->start && where.v < (lp->start + GetLineHeight(dp, pp, lp))) {
  299.             
  300.                 where.v -= lp->start;
  301.                 
  302.                 lineOffset = HitTestDocLine(dp, pp, lp, where);
  303.                 
  304.                 if(lineOffset == lp->numText)
  305.                     endOfLine = true;
  306.                     
  307.                 paraOffset = lineOffset + lp->paraOffset;
  308.                 break;
  309.             }
  310.     }
  311.         
  312.     if(lineIndex == pp->numLines)
  313.         gxEditPostError(dp, gx_edit_internal_fatal_error);
  314.     
  315.     HUnlock((Handle) pp->lines);
  316.     
  317.     *paraOffsetPtr = paraOffset;
  318.     *endOfLinePtr = endOfLine;
  319.     
  320. }
  321.  
  322. void ParagraphPosition(DocPtr dp, ParaPtr pp, short paraOffset, long * start, long * end)
  323. {
  324.     LinePtr        lp;
  325.     short        lineIndex;
  326.     short        lineOffset;
  327.     
  328.     if(pp->dirty)                /* we are using gxLine starts, check if paragraph is dirty */
  329.         CalcStarts(dp, pp, 0);
  330.     
  331.     GetLineIndexAndOffset(dp, pp, paraOffset, &lineIndex, &lineOffset, false);
  332.     
  333.     HLock((Handle) pp->lines);
  334.     
  335.     lp = *pp->lines + lineIndex;
  336.     
  337.     DocLinePosition(lp, start, end);
  338.     
  339.     *start += lp->start;
  340.     *end += lp->start;
  341.     
  342.     HUnlock((Handle) pp->lines);
  343.     
  344. }
  345.  
  346. short GetParagraphOffset(DocPtr dp, ParaPtr pp, short offsetType, short paraOffset)
  347. {
  348.     LinePtr        lp;
  349.     short        lineOffset, lineIndex;
  350.     
  351.     GetLineIndexAndOffset(dp, pp, paraOffset, &lineIndex, &lineOffset, false);
  352.     
  353.     lp = *pp->lines + lineIndex;
  354.     
  355.     if(offsetType == kVisualLeftOffset && lineOffset == 0) {
  356.     
  357.         if(lineIndex == 0)
  358.             gxEditPostError(dp, gx_edit_internal_fatal_error);
  359.             
  360.         lineIndex--;
  361.         lp--;
  362.         lineOffset = lp->numText;
  363.     }
  364.     
  365.     paraOffset = lp->paraOffset;
  366.     
  367.     return(paraOffset + GetLineOffset(dp, pp, lp, offsetType, lineOffset));
  368.     
  369. }
  370.  
  371. void ParagraphClear(DocPtr dp, ParaPtr pp, short paraOffset, short numText)
  372. {
  373.     LinePtr            lp;
  374.     NewRunPtr        rp;
  375.     short            runIndex;
  376.     short            runOffset;
  377.     short            lineIndex;
  378.     short            lineOffset;
  379.     long            size;
  380.     short            index;
  381.     short            lineText;
  382.     short            runNumText;
  383.     short            runText;
  384.     
  385.     if(numText == 0)
  386.         return;
  387.  
  388.     if(paraOffset < 0 || paraOffset >= pp->numText)
  389.         gxEditPostError(dp, gx_edit_internal_fatal_error);
  390.         
  391.     if(paraOffset + numText > pp->numText)
  392.         gxEditPostError(dp, gx_edit_internal_fatal_error);
  393.         
  394.     /* clear the runs */
  395.     
  396.     HLock((Handle) pp->runs);
  397.         
  398.     GetNewRunIndexAndOffset(dp, pp, paraOffset, &runIndex, &runOffset);
  399.     
  400.     runNumText = numText;
  401.  
  402.     index = runIndex;
  403.  
  404.     if(runOffset != 0) {
  405.         
  406.         rp = *pp->runs + index;
  407.     
  408.         runText = rp->numText - runOffset;
  409.         
  410.         if(runText > numText)
  411.             runText = numText;
  412.             
  413.         NewRunClear(dp, rp, runOffset, runText);
  414.         
  415.         runNumText -= runText;
  416.         
  417.         index++;
  418.     }
  419.     
  420.     while(runNumText) {
  421.     
  422.         if(index >= pp->numRuns)
  423.             gxEditPostError(dp, gx_edit_internal_fatal_error);
  424.     
  425.         rp = *pp->runs + index;
  426.  
  427.         if(runNumText >= rp->numText) {
  428.         
  429.             runNumText -= rp->numText;
  430.             
  431.             /* dispose the run */
  432.             
  433.             DisposeNewRun(dp, rp);
  434.             
  435.             pp->numRuns--;
  436.             
  437.             size = (pp->numRuns - index) * sizeof(NewRunRec);
  438.             BlockMove((Ptr) (rp+1), (Ptr) rp, size);
  439.                                     
  440.             HUnlock((Handle) pp->runs);
  441.             
  442.             size = pp->numRuns * sizeof(NewRunRec);
  443.             SetHandleSize((Handle) pp->runs, size);
  444.             
  445.             HLock((Handle) pp->runs);
  446.             
  447.         } else {
  448.     
  449.             NewRunClear(dp, rp, 0, runNumText);
  450.             
  451.             runNumText = 0;
  452.         }
  453.         
  454.     }
  455.     
  456.     HUnlock((Handle) pp->runs);
  457.  
  458.     /* clear the lines */
  459.  
  460.     HLock((Handle) pp->lines);
  461.     
  462.     GetLineIndexAndOffset(dp, pp, paraOffset, &lineIndex, &lineOffset, false);
  463.     
  464.     index = lineIndex;
  465.     
  466.     if(lineOffset != 0) {
  467.     
  468.         lp = *pp->lines + index;
  469.         
  470.         lineText = lp->numText - lineOffset;
  471.         
  472.         if(lineText > numText)
  473.             lineText = numText;
  474.             
  475.         DocLineClear(dp, lp, lineOffset, lineText);
  476.         
  477.         numText -= lineText;
  478.                     
  479.         index++;
  480.             
  481.     }
  482.     
  483.     while(numText > 0) {
  484.     
  485.         lp = *pp->lines + index;
  486.     
  487.         if(numText >= lp->numText) {
  488.         
  489.             numText -= lp->numText;
  490.             
  491.             /* dispose gxLine */
  492.             
  493.             DisposeDocLine(lp);
  494.             
  495.             pp->numLines--;
  496.             
  497.             size = (pp->numLines - index) * sizeof(LineRec);
  498.             BlockMove((Ptr) (lp+1), (Ptr) lp, size);
  499.             
  500.             HUnlock((Handle) pp->lines);
  501.             
  502.             size = pp->numLines * sizeof(LineRec);
  503.             SetHandleSize((Handle) pp->lines, size);
  504.             
  505.             HLock((Handle) pp->lines);
  506.             
  507.         } else {
  508.         
  509.             DocLineClear(dp, lp, 0, numText);
  510.             
  511.             numText = 0;
  512.             
  513.         }
  514.         
  515.     }
  516.     
  517.     HUnlock((Handle) pp->lines);
  518.     
  519.     CalcRunOffsets(dp, pp, runIndex);
  520.     CleanUpRuns(dp, pp, runIndex);
  521.     CalcOffsets(dp, pp, lineIndex);
  522.     
  523.     pp->dirty = true;
  524.  
  525.     if(lineIndex != 0) lineIndex--;        /* might be able to reflow differently now */
  526.     
  527.     (*pp->lines)[lineIndex].reflow = true;
  528.     
  529.     pp->reflow = true;    
  530. }
  531.  
  532. void JoinParagraphs(DocPtr dp, ParaPtr top, ParaPtr bottom)
  533. {
  534.     short            lineIndex;
  535.     long            size;
  536.     LinePtr            lp;
  537.     NewRunPtr        last, first;
  538.     short            runIndex;
  539.     
  540.     /* remove newline from last gxLine of top paragraph */
  541.     
  542.     /* remove it from the run */
  543.     
  544.     last = *top->runs + top->numRuns - 1;
  545.     NewRunClear(dp, last, last->numText - 1, 1);
  546.     
  547.     /* remove it from the gxLine */
  548.     
  549.     lp = *top->lines + top->numLines - 1;
  550.     DocLineClear(dp, lp, lp->numText - 1, 1);
  551.     
  552.     /* save the gxLine index from which we will calc starts and offsets */
  553.     
  554.     lineIndex = top->numLines - 1;
  555.     
  556.     /* join the runs  */
  557.         
  558.     HLock((Handle) top->runs);
  559.     HLock((Handle) bottom->runs);
  560.     
  561.     runIndex = top->numRuns - 1;
  562.         
  563.     last = *top->runs + runIndex;
  564.     first = *bottom->runs;
  565.     
  566.     if(last->styleIndex == first->styleIndex) {
  567.     
  568.         JoinNewRuns(dp, last, first);
  569.         
  570.         HUnlock((Handle) top->runs);
  571.         
  572.         size =  (top->numRuns + bottom->numRuns - 1) * sizeof(NewRunRec);
  573.         SetHandleSize((Handle) top->runs, size);
  574.         
  575.         HLock((Handle) top->runs);
  576.         
  577.         size = (bottom->numRuns - 1) * sizeof(NewRunRec);
  578.         BlockMove((Ptr) (*bottom->runs + 1), (Ptr) (*top->runs + top->numRuns), size);
  579.         
  580.         top->numRuns += bottom->numRuns - 1;
  581.         
  582.     } else {
  583.     
  584.         HUnlock((Handle) top->runs);
  585.         
  586.         size = (top->numRuns + bottom->numRuns) * sizeof(NewRunRec);
  587.         SetHandleSize((Handle) top->runs, size);
  588.         
  589.         HLock((Handle) top->runs);
  590.         
  591.         size = bottom->numRuns * sizeof(NewRunRec);
  592.         BlockMove((Ptr) (*bottom->runs), (Ptr) (*top->runs + top->numRuns), size);
  593.         
  594.         top->numRuns += bottom->numRuns;
  595.  
  596.     }
  597.     
  598.     HUnlock((Handle) top->runs);
  599.     HUnlock((Handle) bottom->runs);
  600.     
  601.     /* join the lines */
  602.     
  603.     size = (top->numLines + bottom->numLines) * sizeof(LineRec);
  604.     SetHandleSize((Handle) top->lines, size);
  605.     
  606.     size = bottom->numLines * sizeof(LineRec);
  607.     BlockMove((Ptr) *bottom->lines, (Ptr) (*top->lines + top->numLines), size);
  608.     
  609.     top->numLines += bottom->numLines;
  610.     
  611.     CalcRunOffsets(dp, top, runIndex);
  612.     CleanUpRuns(dp, top, runIndex);
  613.     CalcOffsets(dp, top, lineIndex);
  614.     
  615.     top->dirty = true;                    /* CalcStarts(dp, top, lineIndex); */
  616.     
  617.     (*top->lines)[lineIndex].reflow = true;
  618.     
  619.     top->reflow = true;
  620.     
  621. }
  622.  
  623. void gxEditDisposeParagraph(DocPtr dp, ParaPtr pp)
  624. {
  625.     LinePtr            lp;
  626.     NewRunPtr        rp;
  627.     short            lineIndex;
  628.     short            runIndex;
  629.     
  630.     HLock((Handle) pp->lines);
  631.     
  632.     lp = *pp->lines;
  633.     
  634.     for(lineIndex=0; lineIndex<pp->numLines; lineIndex++, lp++)
  635.         DisposeDocLine(lp);
  636.     
  637.     HUnlock((Handle) pp->lines);
  638.     
  639.     HLock((Handle) pp->runs);
  640.     
  641.     rp = *pp->runs;
  642.     
  643.     for(runIndex=0; runIndex<pp->numRuns; runIndex++, rp++)
  644.         DisposeNewRun(dp, rp);
  645.         
  646.     HUnlock((Handle) pp->runs);
  647.         
  648.     DisposeHandle((Handle) pp->lines);
  649.     DisposeHandle((Handle) pp->runs);
  650.     
  651. }
  652.  
  653. void SplitParagraph(DocPtr dp, ParaPtr pp, short paraOffset, ParaPtr newPara)
  654. {
  655.     LinePtr            lp;
  656.     short            lineIndex;
  657.     short            lineOffset;
  658.     short            runIndex;
  659.     short            runOffset;
  660.     long                size;
  661.     char                c;
  662.     short            styleIndex;
  663.     
  664.     if(paraOffset < 0 || paraOffset > pp->numText)
  665.         gxEditPostError(dp, gx_edit_internal_fatal_error);
  666.     
  667.     GetNewRunIndexAndOffset(dp, pp, paraOffset, &runIndex, &runOffset);
  668.     
  669.     GetLineIndexAndOffset(dp, pp, paraOffset, &lineIndex, &lineOffset, false);
  670.     
  671.     newPara->numRuns = pp->numRuns - runIndex;
  672.     newPara->numLines = pp->numLines - lineIndex;
  673.     newPara->numText = pp->numText - paraOffset;
  674.     newPara->width = pp->width;
  675.     newPara->layoutOptions = pp->layoutOptions;
  676.     
  677.     /* split runs */
  678.     
  679.     size = sizeof(NewRunRec) * newPara->numRuns;
  680.     newPara->runs = (NewRunHan) NewHandle(size);
  681.     BlockMove((Ptr) (*pp->runs + runIndex), (Ptr) *newPara->runs, size);
  682.  
  683.     if(runOffset || !runIndex) {
  684.     
  685.         HLock((Handle) newPara->runs);
  686.         HLock((Handle) pp->runs);
  687.         
  688.         SplitNewRun(dp, *pp->runs + runIndex, runOffset, *newPara->runs);
  689.         pp->numRuns = runIndex + 1;
  690.         
  691.         HUnlock((Handle) pp->runs);
  692.         HUnlock((Handle) newPara->runs);
  693.  
  694.     } else
  695.         pp->numRuns = runIndex;
  696.     
  697.                     
  698.     /* split lines */
  699.  
  700.     size = sizeof(LineRec) * newPara->numLines;
  701.     newPara->lines = (LineHan) NewHandle(size);
  702.     BlockMove((Ptr) (*pp->lines + lineIndex), (Ptr) *newPara->lines, size);
  703.     
  704.     HLock((Handle) newPara->lines);
  705.     HLock((Handle) pp->lines);
  706.     
  707.     SplitDocLine(dp, *pp->lines + lineIndex, lineOffset, *newPara->lines);
  708.     pp->numLines = lineIndex + 1;
  709.     
  710.     HUnlock((Handle) pp->lines);
  711.     HUnlock((Handle) newPara->lines);
  712.     
  713.     CalcRunOffsets(dp, newPara, 0);
  714.     CleanUpRuns(dp, newPara, 0);            /* this may not be needed */
  715.     CalcOffsets(dp, newPara, 0);
  716.     
  717.     newPara->dirty = true;
  718.     
  719.     (*newPara->lines)[0].reflow = true;
  720.     
  721.     newPara->reflow = true;
  722.     
  723.     /* adjust the original paragraph */
  724.     
  725.     HLock((Handle) pp->lines);
  726.     
  727.     lp = *pp->lines + (pp->numLines - 1);
  728.     
  729.     pp->numText = paraOffset;
  730.     
  731.     pp->dirty = true;
  732.     
  733.     HUnlock((Handle) pp->lines);
  734.     
  735.     SetHandleSize((Handle) pp->lines, pp->numLines * sizeof(LineRec));
  736.     
  737.     SetHandleSize((Handle) pp->runs, pp->numRuns * sizeof(NewRunRec));
  738.     
  739.     /* add newline character at the end of the last line of original paragraph using the style at that point*/
  740.     
  741.     c = '\r';
  742.     styleIndex = (*pp->runs)[pp->numRuns-1].styleIndex;
  743.     
  744.     InsertParagraphText(dp, pp, pp->numText, &c, 1, styleIndex);
  745.     
  746.     CleanUpRuns(dp, pp, 0);                /* this is needed only to take of the possibility of empty runs */
  747.                                     /* this should be cleaned up as empty runs only happen during one specific case
  748.                                         1)  zero length runs are currently not supported
  749.                                         2) this causes zero length runs to be created when a paragraph is spit at the star
  750.                                         *) see above check if(runOffset || !runIndex) */
  751.     
  752. }
  753.  
  754. void GetParagraphAttributes(DocPtr dp, ParaPtr pp, AttrPtr ap, short startParaOffset, short endParaOffset)
  755. {
  756.     NewRunPtr    rp;
  757.     short        startRunIndex;
  758.     short        startRunOffset;
  759.     short        endRunIndex;
  760.     short        endRunOffset;
  761.     short        runIndex;
  762.     
  763.     /* get the attributes from the runs */
  764.     
  765.     HLock((Handle) pp->runs);
  766.         
  767.     GetNewRunIndexAndOffset(dp, pp, startParaOffset, &startRunIndex, &startRunOffset);
  768.     GetNewRunIndexAndOffset(dp, pp, endParaOffset, &endRunIndex, &endRunOffset);
  769.     
  770.     /* fix up end of selection if it is at the start of a run */
  771.     
  772.     if(endRunOffset == 0 && endRunIndex) {
  773.     
  774.         endRunIndex--;
  775.         endRunOffset = (*pp->runs)[endRunIndex].numText;
  776.                 
  777.         /* can this be removed now ??? */
  778.         
  779.         if(startRunIndex > endRunIndex) {
  780.             startRunIndex = endRunIndex;
  781.             startRunOffset = endRunOffset;
  782.         }
  783.         
  784.     }
  785.     
  786.     runIndex = startRunIndex;
  787.     rp = *pp->runs + runIndex;
  788.     
  789.     while(runIndex <= endRunIndex) {
  790.         
  791.         CheckAttributes(dp, rp, ap);
  792.     
  793.         runIndex++;
  794.         rp++;
  795.         
  796.     }
  797.         
  798.     HUnlock((Handle) pp->runs);
  799.  
  800. }
  801.  
  802. #ifdef NO_LONGER_NEEDED
  803. Boolean SetParagraphTextFonts(DocPtr dp, ParaPtr pp, short numFonts, gxFont * srcFonts, gxFont * dstFonts,
  804.                                                     short startParaOffset, short endParaOffset)
  805. {
  806.     short        startLineIndex;
  807.     short        startLineOffset;
  808.     short        endLineIndex;
  809.     short        endLineOffset;
  810.     LinePtr        lp;
  811.     NewRunPtr    rp;
  812.     short        startOffset;
  813.     short        endOffset;
  814.     Boolean        modified;
  815.     short        startRunIndex;
  816.     short        startRunOffset;
  817.     short        endRunIndex;
  818.     short        endRunOffset;
  819.     short        runIndex;
  820.     long        size;
  821.     short        fontIndex;
  822.     gxFont        runTextFont;
  823.     
  824.     /* set the gxFont of the runs */
  825.     
  826.     GetNewRunIndexAndOffset(dp, pp, startParaOffset, &startRunIndex, &startRunOffset);
  827.     GetNewRunIndexAndOffset(dp, pp, endParaOffset, &endRunIndex, &endRunOffset);
  828.     
  829.     /* fix up end of selection if it is at the start of a run */
  830.     
  831.     if(endRunOffset == 0 && endRunIndex) {
  832.     
  833.         endRunIndex--;
  834.         endRunOffset = (*pp->runs)[endRunIndex].numText;
  835.         
  836.         /* when we special case the empty selection -- this can be removed */
  837.         
  838.         if(startRunIndex > endRunIndex) {
  839.             startRunIndex = endRunIndex;
  840.             startRunOffset = endRunOffset;
  841.         }
  842.         
  843.     }
  844.     
  845.     runIndex = startRunIndex;
  846.  
  847.     HLock((Handle) pp->runs);
  848.     
  849.     rp = *pp->runs + runIndex;
  850.     
  851.     modified = false;
  852.     
  853.     while(runIndex <= endRunIndex) {
  854.     
  855.         runTextFont = GetDocStyleTextFont(dp, rp->styleIndex);
  856.     
  857.         for(fontIndex=0; fontIndex<numFonts; fontIndex++)
  858.             if(srcFonts[fontIndex] == runTextFont)
  859.                 break;
  860.         
  861.         if(fontIndex != numFonts && runTextFont != dstFonts[fontIndex]) {
  862.             
  863.             if(runIndex == startRunIndex)
  864.                 startOffset = startRunOffset;
  865.             else
  866.                 startOffset = 0;
  867.                 
  868.             if(runIndex == endRunIndex)
  869.                 endOffset = endRunOffset;
  870.             else
  871.                 endOffset = rp->numText;
  872.                 
  873.             if(startOffset != 0) {
  874.             
  875.                 pp->numRuns++;
  876.                 endRunIndex++;
  877.                 
  878.                 HUnlock((Handle) pp->runs);
  879.                 
  880.                 SetHandleSize((Handle) pp->runs, pp->numRuns * sizeof(NewRunRec));
  881.                 
  882.                 HLock((Handle) pp->runs);
  883.                 
  884.                 rp = *pp->runs + runIndex;
  885.                 
  886.                 size = sizeof(NewRunRec) * (pp->numRuns - runIndex - 2);
  887.                 BlockMove((Ptr) (rp+1), (Ptr) (rp+2), size);
  888.                 
  889.                 SplitNewRun(dp, rp, startOffset, rp+1);
  890.                 
  891.                 runIndex++;
  892.                 rp++;
  893.                 endOffset -= startOffset;
  894.                 startOffset = 0;
  895.                 
  896.             }
  897.             
  898.             if(endOffset != rp->numText) {
  899.             
  900.                 pp->numRuns++;
  901.                 endRunIndex++;
  902.                 
  903.                 HUnlock((Handle) pp->runs);
  904.                 SetHandleSize((Handle) pp->runs, pp->numRuns * sizeof(NewRunRec));
  905.                 
  906.                 HLock((Handle) pp->runs);
  907.                 
  908.                 rp = *pp->runs + runIndex;
  909.                 
  910.                 size = sizeof(NewRunRec) * (pp->numRuns - runIndex - 2);
  911.                 BlockMove((Ptr) (rp+1), (Ptr) (rp+2), size);
  912.                 
  913.                 SplitNewRun(dp, rp, endOffset, rp+1);
  914.                 
  915.                 runIndex++;
  916.                 
  917.             }
  918.             
  919.             if(startOffset == 0 && endOffset == rp->numText)
  920.                 SetNewRunTextFont(dp, rp, dstFonts[fontIndex]);
  921.             else
  922.                 gxEditPostError(dp, gx_edit_internal_fatal_error);
  923.                 
  924.             /* make any lines that contain this run as dirty and need to be reflowed */
  925.             
  926.             GetLineIndexAndOffset(dp, pp, rp->paraOffset, &startLineIndex, &startLineOffset, false);
  927.             GetLineIndexAndOffset(dp, pp, rp->paraOffset + rp->numText, &endLineIndex, &endLineOffset, false);
  928.             
  929.             for(lp = *pp->lines + startLineIndex;startLineIndex <= endLineIndex; startLineIndex++, lp++) {
  930.                 lp->dirty = true;
  931.                 lp->reflow = true;
  932.             }
  933.             
  934.             modified = true;
  935.             
  936.         }
  937.         
  938.         runIndex++;
  939.         rp++;
  940.         
  941.     }
  942.  
  943.     HUnlock((Handle) pp->runs);
  944.     
  945.     /* do calculation starting from startRunIndex -- this is not optimal */
  946.     
  947.     if(modified) {
  948.     
  949.         CalcRunOffsets(dp, pp, startRunIndex);
  950.         CleanUpRuns(dp, pp, startRunIndex);
  951.  
  952.         GetLineIndexAndOffset(dp, pp, startParaOffset, &startLineIndex, &startLineOffset, false);
  953.         CalcOffsets(dp, pp, startLineIndex);
  954.         
  955.         pp->dirty = true;                    /* CalcStarts(dp, pp, startLineIndex); */
  956.         
  957.         pp->reflow = true;
  958.     }
  959.  
  960.     return(modified);
  961.     
  962. }
  963.  
  964. Boolean SetParagraphTextSize(DocPtr dp, ParaPtr pp, short textSize,
  965.                                                     short startParaOffset, short endParaOffset)
  966. {
  967.     short        startLineIndex;
  968.     short        startLineOffset;
  969.     short        endLineIndex;
  970.     short        endLineOffset;
  971.     LinePtr        lp;
  972.     short        startOffset;
  973.     short        endOffset;
  974.     Boolean        modified;
  975.     NewRunPtr    rp;
  976.     short        startRunIndex;
  977.     short        startRunOffset;
  978.     short        endRunIndex;
  979.     short        endRunOffset;
  980.     short        runIndex;
  981.     long        size;
  982.     short        runTextSize;
  983.     
  984.     /* set text size of runs */
  985.     
  986.     GetNewRunIndexAndOffset(dp, pp, startParaOffset, &startRunIndex, &startRunOffset);
  987.     GetNewRunIndexAndOffset(dp, pp, endParaOffset, &endRunIndex, &endRunOffset);
  988.     
  989.     /* fix up end of selection if it is at the start of a run */
  990.     
  991.     if(endRunOffset == 0 && endRunIndex) {
  992.     
  993.         endRunIndex--;
  994.         endRunOffset = (*pp->runs)[endRunIndex].numText;
  995.         
  996.         /* when we special case the empty selection -- this can be removed */
  997.         
  998.         if(startRunIndex > endRunIndex) {
  999.             startRunIndex = endRunIndex;
  1000.             startRunOffset = endRunOffset;
  1001.         }
  1002.         
  1003.     }
  1004.     
  1005.     runIndex = startRunIndex;
  1006.  
  1007.     HLock((Handle) pp->runs);
  1008.     
  1009.     rp = *pp->runs + runIndex;
  1010.     
  1011.     modified = false;
  1012.     
  1013.     while(runIndex <= endRunIndex) {
  1014.     
  1015.         runTextSize = GetDocStyleTextSize(dp, rp->styleIndex);
  1016.     
  1017.         if(runTextSize != textSize) {
  1018.             
  1019.             if(runIndex == startRunIndex)
  1020.                 startOffset = startRunOffset;
  1021.             else
  1022.                 startOffset = 0;
  1023.                 
  1024.             if(runIndex == endRunIndex)
  1025.                 endOffset = endRunOffset;
  1026.             else
  1027.                 endOffset = rp->numText;
  1028.                 
  1029.             if(startOffset != 0) {
  1030.             
  1031.                 pp->numRuns++;
  1032.                 endRunIndex++;
  1033.                 
  1034.                 HUnlock((Handle) pp->runs);
  1035.                 
  1036.                 SetHandleSize((Handle) pp->runs, pp->numRuns * sizeof(NewRunRec));
  1037.                 
  1038.                 HLock((Handle) pp->runs);
  1039.                 
  1040.                 rp = *pp->runs + runIndex;
  1041.                 
  1042.                 size = sizeof(NewRunRec) * (pp->numRuns - runIndex - 2);
  1043.                 BlockMove((Ptr) (rp+1), (Ptr) (rp+2), size);
  1044.                 
  1045.                 SplitNewRun(dp, rp, startOffset, rp+1);
  1046.                 
  1047.                 runIndex++;
  1048.                 rp++;
  1049.                 endOffset -= startOffset;
  1050.                 startOffset = 0;
  1051.                 
  1052.             }
  1053.             
  1054.             if(endOffset != rp->numText) {
  1055.             
  1056.                 pp->numRuns++;
  1057.                 endRunIndex++;
  1058.                 
  1059.                 HUnlock((Handle) pp->runs);
  1060.                 SetHandleSize((Handle) pp->runs, pp->numRuns * sizeof(NewRunRec));
  1061.                 
  1062.                 HLock((Handle) pp->runs);
  1063.                 
  1064.                 rp = *pp->runs + runIndex;
  1065.                 
  1066.                 size = sizeof(NewRunRec) * (pp->numRuns - runIndex - 2);
  1067.                 BlockMove((Ptr) (rp+1), (Ptr) (rp+2), size);
  1068.                 
  1069.                 SplitNewRun(dp, rp, endOffset, rp+1);
  1070.                 
  1071.                 runIndex++;
  1072.                 
  1073.             }
  1074.             
  1075.             if(startOffset == 0 && endOffset == rp->numText)
  1076.                 SetNewRunTextSize(dp, rp, textSize);
  1077.             else
  1078.                 gxEditPostError(dp, gx_edit_internal_fatal_error);
  1079.             
  1080.             /* make any lines that contain this run as dirty and need to be reflowed */
  1081.             
  1082.             GetLineIndexAndOffset(dp, pp, rp->paraOffset, &startLineIndex, &startLineOffset, false);
  1083.             GetLineIndexAndOffset(dp, pp, rp->paraOffset + rp->numText, &endLineIndex, &endLineOffset, false);
  1084.             
  1085.             for(lp = *pp->lines + startLineIndex;startLineIndex <= endLineIndex; startLineIndex++, lp++) {
  1086.                 lp->dirty = true;
  1087.                 lp->reflow = true;
  1088.             }
  1089.             
  1090.             modified = true;
  1091.  
  1092.         }
  1093.         
  1094.         runIndex++;
  1095.         rp++;
  1096.         
  1097.     }
  1098.     
  1099.     HUnlock((Handle) pp->runs);
  1100.         
  1101.     /* do calculation starting from runLineIndex -- this is not optimal */
  1102.     
  1103.     if(modified) {
  1104.  
  1105.         CalcRunOffsets(dp, pp, startRunIndex);
  1106.         CleanUpRuns(dp, pp, startRunIndex);
  1107.  
  1108.         GetLineIndexAndOffset(dp, pp, startParaOffset, &startLineIndex, &startLineOffset, false);
  1109.         CalcOffsets(dp, pp, startLineIndex);
  1110.         
  1111.         pp->dirty = true;                    /* CalcStarts(dp, pp, startLineIndex); */
  1112.  
  1113.         pp->reflow = true;
  1114.     }
  1115.  
  1116.     return(modified);
  1117.     
  1118. }
  1119. #endif
  1120.  
  1121. Boolean SetParagraphStyles(DocPtr dp, ParaPtr pp, short numStyles, short *oldStyles, short *newStyles,
  1122.                                                     short startParaOffset, short endParaOffset)
  1123. {
  1124.     short        startLineIndex;
  1125.     short        startLineOffset;
  1126.     short        endLineIndex;
  1127.     short        endLineOffset;
  1128.     LinePtr        lp;
  1129.     short        startOffset;
  1130.     short        endOffset;
  1131.     Boolean        modified;
  1132.     NewRunPtr    rp;
  1133.     short        startRunIndex;
  1134.     short        startRunOffset;
  1135.     short        endRunIndex;
  1136.     short        endRunOffset;
  1137.     short        runIndex;
  1138.     long        size;
  1139.     short        * stylePtr;
  1140.     short        i;
  1141.         
  1142.     /* set run styles */
  1143.     
  1144.     GetNewRunIndexAndOffset(dp, pp, startParaOffset, &startRunIndex, &startRunOffset);
  1145.     GetNewRunIndexAndOffset(dp, pp, endParaOffset, &endRunIndex, &endRunOffset);
  1146.     
  1147.     /* fix up end of selection if it is at the start of a run */
  1148.     
  1149.     if(endRunOffset == 0 && endRunIndex) {
  1150.     
  1151.         endRunIndex--;
  1152.         endRunOffset = (*pp->runs)[endRunIndex].numText;
  1153.         
  1154.         /* when we special case the empty selection -- this can be removed */
  1155.         
  1156.         if(startRunIndex > endRunIndex) {
  1157.             startRunIndex = endRunIndex;
  1158.             startRunOffset = endRunOffset;
  1159.         }
  1160.         
  1161.     }
  1162.     
  1163.     runIndex = startRunIndex;
  1164.  
  1165.     HLock((Handle) pp->runs);
  1166.     
  1167.     rp = *pp->runs + runIndex;
  1168.     
  1169.     modified = false;
  1170.     
  1171.     while(runIndex <= endRunIndex) {
  1172.     
  1173.         stylePtr = oldStyles;
  1174.         
  1175.         for(i=0; i<numStyles; i++, stylePtr++)
  1176.             if(*stylePtr == rp->styleIndex)
  1177.                 break;
  1178.                 
  1179.         if(i == numStyles)
  1180.             gxEditPostError(dp, gx_edit_internal_fatal_error);
  1181.             
  1182.         if(rp->styleIndex != newStyles[i]) {
  1183.             
  1184.             if(runIndex == startRunIndex)
  1185.                 startOffset = startRunOffset;
  1186.             else
  1187.                 startOffset = 0;
  1188.                 
  1189.             if(runIndex == endRunIndex)
  1190.                 endOffset = endRunOffset;
  1191.             else
  1192.                 endOffset = rp->numText;
  1193.                 
  1194.             if(startOffset != 0) {
  1195.             
  1196.                 pp->numRuns++;
  1197.                 endRunIndex++;
  1198.                 
  1199.                 HUnlock((Handle) pp->runs);
  1200.                 
  1201.                 SetHandleSize((Handle) pp->runs, pp->numRuns * sizeof(NewRunRec));
  1202.                 
  1203.                 HLock((Handle) pp->runs);
  1204.                 
  1205.                 rp = *pp->runs + runIndex;
  1206.                 
  1207.                 size = sizeof(NewRunRec) * (pp->numRuns - runIndex - 2);
  1208.                 BlockMove((Ptr) (rp+1), (Ptr) (rp+2), size);
  1209.                 
  1210.                 SplitNewRun(dp, rp, startOffset, rp+1);
  1211.                 
  1212.                 runIndex++;
  1213.                 rp++;
  1214.                 endOffset -= startOffset;
  1215.                 startOffset = 0;
  1216.                 
  1217.             }
  1218.             
  1219.             if(endOffset != rp->numText) {
  1220.             
  1221.                 pp->numRuns++;
  1222.                 endRunIndex++;
  1223.                 
  1224.                 HUnlock((Handle) pp->runs);
  1225.                 SetHandleSize((Handle) pp->runs, pp->numRuns * sizeof(NewRunRec));
  1226.                 
  1227.                 HLock((Handle) pp->runs);
  1228.                 
  1229.                 rp = *pp->runs + runIndex;
  1230.                 
  1231.                 size = sizeof(NewRunRec) * (pp->numRuns - runIndex - 2);
  1232.                 BlockMove((Ptr) (rp+1), (Ptr) (rp+2), size);
  1233.                 
  1234.                 SplitNewRun(dp, rp, endOffset, rp+1);
  1235.                 
  1236.                 runIndex++;
  1237.             }
  1238.             
  1239.             if(startOffset == 0 && endOffset == rp->numText) {
  1240.             
  1241.                 /* BUG ALERT -- This assumes that the caller will never use this call
  1242.                    to change the gxFont or size */
  1243.                 
  1244.                 DecrementDocStyleRefCount(dp, rp->styleIndex);
  1245.                 
  1246.                 rp->styleIndex = newStyles[i];
  1247.                 
  1248.                 IncrementDocStyleRefCount(dp, rp->styleIndex);
  1249.                 
  1250.             } else
  1251.                 gxEditPostError(dp, gx_edit_internal_fatal_error);
  1252.             
  1253.             /* make any lines that contain this run as dirty and need to be reflowed */
  1254.             
  1255.             GetLineIndexAndOffset(dp, pp, rp->paraOffset, &startLineIndex, &startLineOffset, false);
  1256.             GetLineIndexAndOffset(dp, pp, rp->paraOffset + rp->numText, &endLineIndex, &endLineOffset, false);
  1257.             
  1258.             for(lp = *pp->lines + startLineIndex;startLineIndex <= endLineIndex; startLineIndex++, lp++) {
  1259.                 lp->dirty = true;
  1260.                 lp->reflow = true;
  1261.             }
  1262.             
  1263.             modified = true;
  1264.  
  1265.             
  1266.         }
  1267.         
  1268.         runIndex++;
  1269.         rp++;
  1270.         
  1271.     }
  1272.     
  1273.     HUnlock((Handle) pp->runs);
  1274.         
  1275.     /* do calculation starting from runLineIndex -- this is not optimal */
  1276.     
  1277.     if(modified) {
  1278.  
  1279.         CalcRunOffsets(dp, pp, startRunIndex);
  1280.         CleanUpRuns(dp, pp, startRunIndex);
  1281.  
  1282.         GetLineIndexAndOffset(dp, pp, startParaOffset, &startLineIndex, &startLineOffset, false);
  1283.         CalcOffsets(dp, pp, startLineIndex);
  1284.         
  1285.         pp->dirty = true;                    /* CalcStarts(dp, pp, startLineIndex); */
  1286.  
  1287.         pp->reflow = true;
  1288.     }
  1289.  
  1290.     return(modified);
  1291.     
  1292. }
  1293.  
  1294. short GetParagraphHeight(DocPtr dp, ParaPtr pp)
  1295. {
  1296.     if(pp->dirty)
  1297.         CalcStarts(dp, pp, 0);
  1298.         
  1299.     return(pp->height);
  1300. }
  1301.  
  1302. static void ReflowParagraphAtIndex(DocPtr dp, ParaPtr pp, short lineIndex)
  1303. {
  1304.     LinePtr                lp;
  1305.     short                i;
  1306.     long                textRunCount;
  1307.     short                * textRunLengths;
  1308.     void                ** textPtrs;
  1309.     long                styleRunCount;
  1310.     short                * styleRunLengths;
  1311.     gxStyle                * styles;
  1312.     short                breakPoint;
  1313.     short                lastBreakPoint;
  1314.     short                ** breakPoints;
  1315.     short                * bp;
  1316.     short                numBreakPoints;
  1317.     short                numLayoutText;
  1318.     gxShape                layout;
  1319.     short                startLineIndex;
  1320.     short                numLines;
  1321.     short                numText;
  1322.     long                size;
  1323.     short                paraOffset;
  1324.     short                startRunIndex;
  1325.     short                startRunOffset;
  1326.     short                runOffset;
  1327.     NewRunPtr            rp;
  1328.     
  1329.     if(lineIndex < 0 || lineIndex >= pp->numLines)
  1330.         gxEditPostError(dp, gx_edit_internal_fatal_error);
  1331.     
  1332.     startLineIndex = lineIndex;
  1333.     numLines = pp->numLines - lineIndex;
  1334.  
  1335.     /* build a layout of all the runs starting with the gxLine lineIndex */
  1336.     
  1337.     GetNewRunIndexAndOffset(dp, pp, (*pp->lines)[lineIndex].paraOffset, &startRunIndex, &startRunOffset);
  1338.     
  1339.     textRunCount = pp->numRuns - startRunIndex;
  1340.  
  1341.     HLock((Handle) pp->lines);
  1342.     
  1343.     /* setup the run info to be passed to GXNewLayout */
  1344.     
  1345.     textRunLengths = (short *) NewPtr(textRunCount * sizeof(short));
  1346.     textPtrs = (void **) NewPtr(textRunCount * sizeof(void *));
  1347.     styles = (gxStyle *) NewPtr(textRunCount * sizeof(gxStyle));
  1348.     
  1349.     runOffset = startRunOffset;
  1350.     rp = *pp->runs + startRunIndex;
  1351.     
  1352.     for(i=0; i < textRunCount; i++, rp++) {
  1353.     
  1354.         textRunLengths[i] = (rp->numText - runOffset);
  1355.         styles[i] = GetDocStyle(dp, rp->styleIndex)->textStyle;
  1356.         
  1357.         HLock((Handle) rp->text);
  1358.         
  1359.         textPtrs[i] = (Ptr) *rp->text + (runOffset);
  1360.         
  1361.         runOffset = 0;
  1362.     }
  1363.  
  1364.     styleRunCount = textRunCount;
  1365.     styleRunLengths = textRunLengths;
  1366.     
  1367.     /* allocate the new layout */
  1368.     
  1369.     layout = GXNewLayout(textRunCount, textRunLengths, (void *) textPtrs,
  1370.                                 styleRunCount, styleRunLengths, styles, 0, nil, nil,
  1371.                                 nil, nil);
  1372.     
  1373.     /* now we can work with the layout to find the break points */
  1374.     
  1375.     numLayoutText = pp->numText - (*pp->lines)[lineIndex].paraOffset;
  1376.     lastBreakPoint = 0;
  1377.     
  1378.     breakPoints = (short **) NewHandle(0);
  1379.     numBreakPoints = 0;
  1380.     
  1381.     paraOffset = (*pp->lines)[startLineIndex].paraOffset;
  1382.     
  1383.     do {
  1384.     
  1385.         breakPoint = GXGetLayoutBreakOffset(layout, lastBreakPoint, ff(pp->width),
  1386.                                             0, nil, nil, nil, nil);
  1387.         
  1388.         if(breakPoint == (numLayoutText - 1))    /* don't break at end of paragraph */
  1389.             breakPoint++;
  1390.                     
  1391.         if(breakPoint  != numLayoutText) {
  1392.             
  1393.             breakPoint = FindWordBreak(dp, pp, lastBreakPoint + paraOffset, breakPoint + paraOffset);
  1394.             breakPoint -= paraOffset;
  1395.             
  1396.         }
  1397.                                                                         
  1398.         PtrAndHand((Ptr) &breakPoint, (Handle) breakPoints, sizeof(short));
  1399.         numBreakPoints++;
  1400.         
  1401.         lastBreakPoint = breakPoint;
  1402.                 
  1403.     } while(breakPoint != numLayoutText);
  1404.     
  1405.     /* unlock the run text */
  1406.     
  1407.     rp = *pp->runs + startRunIndex;
  1408.     for(i=0; i < textRunCount; i++, rp++)
  1409.         HUnlock((Handle) rp->text);
  1410.     
  1411.     
  1412.     /* free up temporary data structures */
  1413.     
  1414.     DisposePtr((Ptr) textRunLengths);
  1415.     DisposePtr((Ptr) textPtrs);
  1416.     DisposePtr((Ptr) styles);
  1417.     
  1418.     GXDisposeShape(layout);
  1419.     
  1420.     /* now fix up the actual lines */
  1421.     
  1422.     lp = *pp->lines + lineIndex;
  1423.     
  1424.     HLock((Handle) breakPoints);
  1425.     
  1426.     bp = *breakPoints;
  1427.     numText = *bp;
  1428.     
  1429.     for(i=0; i < numBreakPoints; i++, bp++) {
  1430.     
  1431.         while(lp->numText != numText) {
  1432.         
  1433.             if(lp->numText < numText) {
  1434.             
  1435.                 if(lineIndex == pp->numLines-1)
  1436.                     gxEditPostError(dp, gx_edit_internal_fatal_error);
  1437.             
  1438.                 JoinDocLines(lp, lp+1);
  1439.                 
  1440.                 size = (pp->numLines - lineIndex - 2) * sizeof(LineRec);
  1441.                 
  1442.                 BlockMove((Ptr) (lp+2), (Ptr) (lp+1), size);
  1443.                 
  1444.                 pp->numLines--;
  1445.                 
  1446.                 HUnlock((Handle) pp->lines);
  1447.                 
  1448.                 SetHandleSize((Handle) pp->lines, pp->numLines * sizeof(LineRec));
  1449.                 
  1450.                 HLock((Handle) pp->lines);
  1451.                 
  1452.                 lp = *pp->lines + lineIndex;
  1453.                 
  1454.             } else {
  1455.             
  1456.                 HUnlock((Handle) pp->lines);
  1457.                 
  1458.                 pp->numLines++;
  1459.                 
  1460.                 SetHandleSize((Handle) pp->lines, pp->numLines * sizeof(LineRec));
  1461.                 
  1462.                 HLock((Handle) pp->lines);
  1463.                 
  1464.                 lp = *pp->lines + lineIndex;
  1465.                                     
  1466.                 size = (pp->numLines - 2 - lineIndex) * sizeof(LineRec);
  1467.                 
  1468.                 BlockMove((Ptr) (lp+1), (Ptr) (lp+2), size);
  1469.                 
  1470.                 SplitDocLine(dp, lp, numText, lp+1);
  1471.                 
  1472.             }
  1473.             
  1474.         }
  1475.                 
  1476.         lp++;
  1477.         lineIndex++;
  1478.         
  1479.         numText = *(bp+1) - *bp;
  1480.                             
  1481.     }
  1482.     
  1483.     HUnlock((Handle) breakPoints);
  1484.     
  1485.     DisposeHandle((Handle) breakPoints);
  1486.         
  1487.     HUnlock((Handle) pp->lines);
  1488.     
  1489.     /* calculate starts and offsets -- set height */
  1490.     
  1491.     CalcOffsets(dp, pp, startLineIndex);
  1492.     
  1493.     pp->dirty = true;                            /* CalcStarts(dp, pp, startLineIndex); */
  1494.     
  1495. }
  1496.  
  1497. static void CalcRunOffsets(DocPtr dp, ParaPtr pp, short runIndex)
  1498. {
  1499.     short                paraOffset;
  1500.     NewRunPtr            rp;
  1501.     
  1502.     /* do the runs */
  1503.     
  1504.     if(runIndex < 0 || runIndex >= pp->numRuns)
  1505.         gxEditPostError(dp, gx_edit_internal_fatal_error);
  1506.     
  1507.     if(pp->numRuns == 0)
  1508.         return;
  1509.  
  1510.     rp = *pp->runs + runIndex;
  1511.     
  1512.     if(runIndex == 0) {
  1513.     
  1514.         rp->paraOffset = 0;
  1515.         
  1516.     } else {
  1517.     
  1518.         runIndex--;
  1519.         rp--;
  1520.         
  1521.     }
  1522.     
  1523.     paraOffset = rp->paraOffset + rp->numText;
  1524.     
  1525.     runIndex++;
  1526.     rp++;
  1527.  
  1528.     for(; runIndex < pp->numRuns; runIndex++, rp++) {
  1529.     
  1530.         rp->paraOffset = paraOffset;
  1531.  
  1532.         paraOffset += rp->numText;
  1533.         
  1534.     }
  1535.     
  1536. }
  1537.  
  1538. static void CalcOffsets(DocPtr dp, ParaPtr pp, short lineIndex)
  1539. {
  1540.     LinePtr                lp;
  1541.     short                paraOffset;
  1542.         
  1543.     if(lineIndex < 0 || lineIndex >= pp->numLines)
  1544.         gxEditPostError(dp, gx_edit_internal_fatal_error);
  1545.     
  1546.     HLock((Handle) pp->lines);
  1547.     
  1548.     lp = *pp->lines + lineIndex;
  1549.     
  1550.     if(lineIndex == 0) {
  1551.     
  1552.         lp->paraOffset = 0;
  1553.         
  1554.     } else {
  1555.     
  1556.         lp--;
  1557.         lineIndex--;
  1558.         
  1559.     }
  1560.     
  1561.     paraOffset = lp->paraOffset + lp->numText;
  1562.     
  1563.     lineIndex++;
  1564.     lp++;
  1565.         
  1566.     for(; lineIndex < pp->numLines; lineIndex++, lp++) {
  1567.     
  1568.         lp->paraOffset = paraOffset;
  1569.         paraOffset += lp->numText;        
  1570.         
  1571.     }
  1572.     
  1573.     pp->numText = paraOffset;
  1574.     
  1575.     HUnlock((Handle) pp->lines);
  1576.     
  1577. }
  1578.  
  1579. static void CalcStarts(DocPtr dp, ParaPtr pp, short lineIndex)
  1580. {
  1581.     LinePtr                lp;
  1582.     short                start;
  1583.         
  1584.     if(lineIndex < 0 || lineIndex >= pp->numLines)
  1585.         gxEditPostError(dp, gx_edit_internal_fatal_error);
  1586.     
  1587.     HLock((Handle) pp->lines);
  1588.     
  1589.     lp = *pp->lines + lineIndex;
  1590.     
  1591.     if(lineIndex == 0) {
  1592.     
  1593.         lp->start = 0;
  1594.         
  1595.     } else {
  1596.     
  1597.         lp--;
  1598.         lineIndex--;
  1599.         
  1600.     }
  1601.     
  1602.     start = lp->start + GetLineHeight(dp, pp, lp);
  1603.     
  1604.     lineIndex++;
  1605.     lp++;
  1606.         
  1607.     for(; lineIndex < pp->numLines; lineIndex++, lp++) {
  1608.     
  1609.         if(lp->start != start)
  1610.             lp->drawn = false;        /* the gxLine has moved -- redraw */
  1611.     
  1612.         lp->start = start;
  1613.  
  1614.         start += GetLineHeight(dp, pp, lp);
  1615.         
  1616.     }
  1617.     
  1618.     pp->height = start;
  1619.     
  1620.     HUnlock((Handle) pp->lines);
  1621.     
  1622.     pp->dirty = false;
  1623. }
  1624.  
  1625. static short FindWordBreak(DocPtr dp, ParaPtr pp, short startOffset, short endOffset)
  1626. {
  1627.     NewRunPtr            rp;
  1628.     short                remain;
  1629.     short                runIndex;
  1630.     short                runOffset;
  1631.     short                textToCheck;
  1632.     char                    * ptr;
  1633.     StylePtr                style;
  1634.     
  1635.     textToCheck = endOffset - startOffset;
  1636.     
  1637.     rp = *pp->runs;
  1638.     
  1639.     for(runIndex = 0; runIndex < pp->numRuns; runIndex++, rp++)
  1640.         if((rp->paraOffset + rp->numText) >= endOffset)
  1641.             break;
  1642.             
  1643.     if(runIndex == pp->numRuns)
  1644.         gxEditPostError(dp, gx_edit_internal_fatal_error);
  1645.         
  1646.     remain = rp->paraOffset + rp->numText - endOffset - 1;
  1647.     ptr = (char *) *rp->text + endOffset - rp->paraOffset;
  1648.     
  1649.     /* scan forward for the first non-space */
  1650.     while (runIndex < pp->numRuns)
  1651.     {
  1652.         style = GetDocStyle(dp, rp->styleIndex);
  1653.         
  1654.         if (style->platform != gxGlyphPlatform)
  1655.         {
  1656.             while (remain > 0)
  1657.             {
  1658.                 endOffset += 1;
  1659.                 if (*ptr == ' ')
  1660.                 {
  1661.                     remain -= 1;
  1662.                     ptr += 1;
  1663.                 }
  1664.                 else
  1665.                     break;
  1666.             }
  1667.             
  1668.             if (remain > 0)
  1669.                 break;
  1670.         }
  1671.         
  1672.         runIndex += 1;
  1673.         rp += 1;
  1674.         remain = rp->numText;
  1675.         ptr = (char *) *rp->text;
  1676.     }
  1677.     
  1678.     if (runIndex == pp->numRuns)
  1679.         return endOffset;
  1680.  
  1681.     runOffset = endOffset - rp->paraOffset;
  1682.     
  1683.     /* now scan backwards for the first space */
  1684.     
  1685.     for(; runIndex >= 0; runIndex--, rp--) {
  1686.     
  1687.         /* skip over runs of glyph indicies */
  1688.         
  1689.         style = GetDocStyle(dp, rp->styleIndex);
  1690.         
  1691.         if(style->platform != gxGlyphPlatform) {
  1692.             
  1693.             /* BUG ALERT!!!! We must put code in that handles the finding
  1694.                of separators nomatter what the text size.  This code is wrong
  1695.                when two byte text data is being traversed */
  1696.         
  1697.             ptr = (char *) *rp->text + runOffset - 1;
  1698.     
  1699.             for(; runOffset > 0; runOffset--, ptr--, textToCheck--) {
  1700.             
  1701.                 if(textToCheck <= 0)
  1702.                     return(endOffset);
  1703.             
  1704.                 if(*ptr == ' ') 
  1705.                     return(rp->paraOffset + runOffset);
  1706.                     
  1707.             }
  1708.             
  1709.         } else {
  1710.         
  1711.             textToCheck -= runOffset;
  1712.         
  1713.             if(textToCheck <= 0)
  1714.                 return(endOffset);
  1715.                 
  1716.         }
  1717.                 
  1718.         if(runIndex)
  1719.             runOffset = (rp-1)->numText;
  1720.             
  1721.     }
  1722.     
  1723.     return(endOffset);
  1724.     
  1725. }
  1726.  
  1727. static void CheckAttributes(DocPtr dp, NewRunPtr rp, AttrPtr ap)
  1728. {
  1729.     gxFont        * fp;
  1730.     short        * sp;
  1731.     short        i;
  1732.     gxFont        runTextFont;
  1733.     short        runTextSize;
  1734.     
  1735.     runTextFont = GetDocStyleTextFont(dp, rp->styleIndex);
  1736.     runTextSize = GetDocStyleTextSize(dp, rp->styleIndex);
  1737.     
  1738.     if(ap->start) {
  1739.  
  1740.         ap->fonts = (gxFont **) NewHandle(sizeof(gxFont));
  1741.         ap->numFonts = 1;
  1742.         
  1743.         (*ap->fonts)[0] = runTextFont;
  1744.  
  1745.         ap->styles = (short **) NewHandle(sizeof(short));
  1746.         ap->numStyles = 1;
  1747.         
  1748.         (*ap->styles)[0] = rp->styleIndex;
  1749.         
  1750.         if(rp->styleIndex < 0 || rp->styleIndex >= dp->numStyles)
  1751.             gxEditPostError(dp, gx_edit_internal_fatal_error);
  1752.             
  1753.         ap->size = runTextSize;
  1754.         ap->start = false;
  1755.         
  1756.     } else {
  1757.     
  1758.         /* add the gxFont */
  1759.         
  1760.         fp = *ap->fonts;
  1761.         
  1762.         for(i=0; i<ap->numFonts; i++, fp++)
  1763.             if(*fp == runTextFont)
  1764.                 break;
  1765.                 
  1766.         if(i == ap->numFonts) {
  1767.         
  1768.             ap->numFonts++;
  1769.             SetHandleSize((Handle) ap->fonts, ap->numFonts * sizeof(gxFont));
  1770.             
  1771.             (*ap->fonts)[ap->numFonts-1] = runTextFont;
  1772.                         
  1773.         }
  1774.  
  1775.         /* add the style */
  1776.         
  1777.         sp = *ap->styles;
  1778.         
  1779.         for(i=0; i<ap->numStyles; i++, sp++)
  1780.             if(*sp == rp->styleIndex)
  1781.                 break;
  1782.                 
  1783.         if(i == ap->numStyles) {
  1784.         
  1785.             ap->numStyles++;
  1786.             SetHandleSize((Handle) ap->styles, ap->numStyles * sizeof(short));
  1787.             
  1788.             (*ap->styles)[ap->numStyles-1] = rp->styleIndex;
  1789.             
  1790.             if(rp->styleIndex < 0 || rp->styleIndex >= dp->numStyles)
  1791.                 gxEditPostError(dp, gx_edit_internal_fatal_error);
  1792.             
  1793.         }
  1794.                     
  1795.         if(ap->size != runTextSize)
  1796.             ap->size = kUndefinedSize;
  1797.                 
  1798.     }
  1799.     
  1800. }
  1801.  
  1802. static void CleanUpRuns(DocPtr dp, ParaPtr pp, short startRunIndex)
  1803. {
  1804.     NewRunPtr        rp;
  1805.     short            runIndex;
  1806.     
  1807.     if(startRunIndex < 0 || startRunIndex >= pp->numRuns)
  1808.         gxEditPostError(dp, gx_edit_internal_fatal_error);
  1809.     
  1810.     if(pp->numRuns == 0)
  1811.         return;
  1812.  
  1813.     if(startRunIndex > 0)
  1814.         startRunIndex--;
  1815.         
  1816.     HLock((Handle) pp->runs);
  1817.     
  1818.     runIndex = startRunIndex;
  1819.     rp = *pp->runs + runIndex;
  1820.     
  1821.     while(runIndex < pp->numRuns) {
  1822.     
  1823.         if (rp->numText == 0) {
  1824.         
  1825.             /* remove empty runs */
  1826.     
  1827.             DisposeNewRun(dp, rp);
  1828.             
  1829.             BlockMove((Ptr) (rp+1), (Ptr) rp, (pp->numRuns - runIndex - 1) * sizeof(NewRunRec));
  1830.             pp->numRuns--;
  1831.             
  1832.             HUnlock((Handle) pp->runs);
  1833.             
  1834.             SetHandleSize((Handle) pp->runs, pp->numRuns * sizeof(NewRunRec));
  1835.             
  1836.             HLock((Handle) pp->runs);
  1837.             
  1838.             rp = *pp->runs + runIndex;
  1839.             
  1840.         } else {
  1841.             runIndex++;
  1842.             rp++;
  1843.         }
  1844.         
  1845.     }
  1846.     
  1847.     runIndex = startRunIndex;
  1848.     rp = *pp->runs + runIndex;
  1849.     
  1850.     while(runIndex < pp->numRuns) {
  1851.     
  1852.         if(runIndex < (pp->numRuns - 1) && (rp->styleIndex == (rp+1)->styleIndex)) {
  1853.         
  1854.             /* join like runs */
  1855.     
  1856.             JoinNewRuns(dp, rp, (rp + 1));
  1857.             
  1858.             pp->numRuns--;
  1859.             
  1860.             BlockMove((Ptr) (rp + 2), (Ptr) (rp+1), (pp->numRuns - runIndex - 1) * sizeof(NewRunRec));
  1861.         
  1862.             HUnlock((Handle) pp->runs);
  1863.             
  1864.             SetHandleSize((Handle) pp->runs, pp->numRuns * sizeof(NewRunRec));
  1865.             
  1866.             HLock((Handle) pp->runs);
  1867.             
  1868.             rp = *pp->runs + runIndex;
  1869.             
  1870.         } else {
  1871.             runIndex++;
  1872.             rp++;
  1873.         }
  1874.         
  1875.     }
  1876.     
  1877.     HUnlock((Handle) pp->runs);
  1878.     
  1879. }
  1880.